package com.example.apartment.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.apartment.common.ApiRestResponse;
import com.example.apartment.common.MD5Utils;
import com.example.apartment.common.RespException;
import com.example.apartment.common.RespExceptionEnum;
import com.example.apartment.domain.*;
import com.example.apartment.mapper.BedMapper;
import com.example.apartment.mapper.BuildingMapper;
import com.example.apartment.mapper.RoomMapper;
import com.example.apartment.mapper.StudentMapper;
import com.example.apartment.service.StudentService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * 学生业务层实现类
 *
 * @author wuzexin
 * @date 2021/10/28 14:28
 */
@Service
public class StudentServiceImpl implements StudentService {

    @Resource
    private StudentMapper studentMapper;
    @Resource
    private BuildingMapper buildingMapper;
    @Resource
    private RoomMapper roomMapper;
    @Resource
    private BedMapper bedMapper;

    /**
     * 学生用户登录
     *
     * @param sid      学号
     * @param password 密码
     * @return 返回学生信息
     */
    @Override
    public Student login(String sid, String password) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("sid", sid);
        // 密码进行MD5加密
        queryWrapper.eq("password", MD5Utils.getMD5Str(password));
        // 进行登录
        Student student = studentMapper.selectOne(queryWrapper);
        // 用户名或密码错误，抛出异常
        if (student == null) {
            throw new RespException(RespExceptionEnum.PASSWORD_WRONG);
        }
        // 登录成功，返回用户学生信息
        return student;
    }

    /**
     * 查询学生信息
     *
     * @param admin 管理员信息
     * @return 学生列表
     */
    @Override
    public List<Student> select(Admin admin) {

        int role = admin.getRole();
        List<Student> list = null;

        if (role == 1) {
            // 系统管理员可以查询所有宿舍信息
            list = studentMapper.selectList(null);

        } else if (role == 2) {
            // 宿舍管理员只能查询所负责楼栋的宿舍信息
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("building_id", admin.getBuildingId());
            list = studentMapper.selectList(queryWrapper);

        } else {
            throw new RespException(RespExceptionEnum.NEED_PERMISSIONS);
        }

        // 将宿舍楼id、宿舍id、床位id转为对应的名字和号码
        for (Student student : list) {
            // 获取学生对应的buildingId, roomId, bedId
            Integer buildingId = student.getBuildingId();
            Integer roomId = student.getRoomId();
            Integer bedId = student.getBedId();

            if (student.getBuildingId() != null) {
                Building building = buildingMapper.selectById(buildingId);
                student.setBuildingName(building.getBuildingName());
            }
            if (student.getRoomId() != null) {
                Room room = roomMapper.selectById(roomId);
                student.setRoomNum(room.getRoomNum());
            }
            if (student.getBedId() != null) {
                Bed bed = bedMapper.selectById(bedId);
                student.setBedNum(bed.getBedNum());
            }
        }

        return list;
    }

    /**
     * 添加学生功能
     *
     * @param admin        管理员信息
     * @param sid          学号
     * @param name         姓名
     * @param sex          性别
     * @param nation       民族
     * @param major        专业
     * @param classroom    班级
     * @param cellphone    手机号码
     * @param password     密码
     * @param buildingName 宿舍楼名字
     * @param roomNum      宿舍号
     * @param bedNum       床位号
     * @return 学生信息
     */
    @Override
    public Student addStudent(Admin admin, String sid, String name, Integer sex, String nation, String major, String classroom, String cellphone, String password, String buildingName, Integer roomNum, Integer bedNum) {

        // 判断管理员权限
        if (admin.getRole() != 1 && admin.getRole() != 2) {
            throw new RespException(RespExceptionEnum.NEED_PERMISSIONS);
        }

        // 判断学号是否已经存在
        QueryWrapper sidQueryWrapper = new QueryWrapper();
        sidQueryWrapper.eq("sid", sid);
        Student student = studentMapper.selectOne(sidQueryWrapper);
        // 如果学号已存在，抛出异常
        if (student != null) {
            throw new RespException(RespExceptionEnum.SID_IS_EXISTS);
        }

        Integer buildingId = null;
        Integer roomId = null;
        Integer bedId = null;


        if (!buildingName.equals("-1")) {
            // 判断宿舍楼是否存在
            QueryWrapper buildingQueryWrapper = new QueryWrapper();
            buildingQueryWrapper.eq("building_name", buildingName);
            Building building = buildingMapper.selectOne(buildingQueryWrapper);
            // 如果宿舍楼不存在，抛出异常
            if (building == null) {
                throw new RespException(RespExceptionEnum.BUILDING_NOT_EXISTS);
            }
            // 如果存在 保存building_id
            buildingId = building.getId();

            if (roomNum != null) {
                // 判断宿舍是否存在
                QueryWrapper roomQueryWrapper = new QueryWrapper();
                roomQueryWrapper.eq("building_id", buildingId);
                roomQueryWrapper.eq("room_num", roomNum);
                Room room = roomMapper.selectOne(roomQueryWrapper);
                // 如果房间不存在，则抛出异常
                if (room == null) {
                    throw new RespException(RespExceptionEnum.ROOM_NOT_EXISTS);
                }
                // 如果存在， 保存room_id
                roomId = room.getId();
            }

            if (roomNum != null && bedNum != null) {
                // 判断床位是否存在
                QueryWrapper bedQueryWrapper = new QueryWrapper();
                bedQueryWrapper.eq("building_id", buildingId);
                bedQueryWrapper.eq("room_id", roomId);
                bedQueryWrapper.eq("bed_num", bedNum);
                Bed bed = bedMapper.selectOne(bedQueryWrapper);
                // 如果床位不存在，则抛出异常
                if (bed == null) {
                    throw new RespException(RespExceptionEnum.BED_NOT_EXISTS);
                }
                // 如果存在，保存bed_id
                bedId = bed.getId();

                // 判断床位是否已经有人住
                QueryWrapper liveQueryWrapper = new QueryWrapper();
                liveQueryWrapper.eq("building_id", buildingId);
                liveQueryWrapper.eq("room_id", roomId);
                liveQueryWrapper.eq("bed_id", bedId);
                Student student1 = studentMapper.selectOne(liveQueryWrapper);
                // 如果已有人住，则抛出异常
                if (student1 != null) {
                    throw new RespException(RespExceptionEnum.BED_HAS_PERSON);
                }
            }
        }

        // 创建一个student对象
        Student stu = new Student();
        stu.setSid(sid);
        stu.setName(name);
        stu.setSex(sex);
        stu.setNation(nation);
        stu.setMajor(major);
        stu.setClassroom(classroom);
        stu.setCellphone(cellphone);
        stu.setPassword(MD5Utils.getMD5Str(password));
        if (buildingId != null) {
            stu.setBuildingId(buildingId);
        }
        if (roomId != null) {
            stu.setRoomId(roomId);
        }
        if (bedId != null && roomId != null) {
            stu.setBedId(bedId);
        }

        // 写入数据库
        int insert = studentMapper.insert(stu);

        // 如果写入数据不为1,抛出新增失败异常
        if (insert != 1) {
            throw new RespException(RespExceptionEnum.INSERT_FAILED);
        }

        return stu;
    }

    /**
     * 删除学生功能
     *
     * @param admin 管理员信息
     * @param id    要删除的学生id
     */
    @Override
    public void delStudent(Admin admin, Integer id) {

        // 获取该学生所在的宿舍楼
        Student stu = studentMapper.selectById(id);
        Integer buildingId = stu.getBuildingId();

        // 判断用户是否为系统管理员 或者为该楼栋的宿舍管理员
        if (admin.getRole() != 1 && !(admin.getRole() == 2 && admin.getBuildingId().equals(buildingId))) {
            // 不是则抛出权限不够异常
            throw new RespException(RespExceptionEnum.NEED_PERMISSIONS);
        }

        // 操作数据库，删除学生
        int del = studentMapper.deleteById(id);

        // 如果操作结果不为1， 抛出删除删除失败异常
        if (del != 1) {
            throw new RespException(RespExceptionEnum.DELETE_FAILED);
        }
    }

    /**
     * 根据id查询学生信息
     *
     * @param admin 管理员信息
     * @param id    学生id
     * @return 学生信息
     */
    @Override
    public Student selectById(Admin admin, Integer id) {

        // 获取该学生所在的宿舍楼
        Student stu = studentMapper.selectById(id);

        // 判断id是否存在，不存在则抛出异常
        if (stu == null) {
            throw new RespException(RespExceptionEnum.ID_NOT_EXISTS);
        }

        // 获取学生所属宿舍楼
        Integer buildingId = stu.getBuildingId();

        // 判断用户是否为系统管理员 或者为该楼栋的宿舍管理员
        if (admin.getRole() != 1 && !(admin.getRole() == 2 && admin.getBuildingId().equals(buildingId))) {
            // 不是则抛出权限不够异常
            throw new RespException(RespExceptionEnum.NEED_PERMISSIONS);
        }

        // 查询对应的buildingName, roomNum, bedNum
        if (stu.getBuildingId() != null) {
            Building building = buildingMapper.selectById(buildingId);
            stu.setBuildingName(building.getBuildingName());
        }
        if (stu.getRoomId() != null) {
            Room room = roomMapper.selectById(stu.getRoomId());
            stu.setRoomNum(room.getRoomNum());
        }
        if (stu.getBedId() != null) {
            Bed bed = bedMapper.selectById(stu.getBedId());
            stu.setBedNum(bed.getBedNum());
        }

        return stu;
    }

    /**
     * 修改学生信息
     *
     * @param admin        管理员信息
     * @param id           学生主键id
     * @param sid          学号
     * @param name         姓名
     * @param sex          性别
     * @param nation       民族
     * @param major        专业
     * @param classroom    班级
     * @param cellphone    手机号码
     * @param password     密码
     * @param buildingName 宿舍楼名字
     * @param roomNum      宿舍号
     * @param bedNum       床位号
     * @return 学生信息
     */
    @Override
    public Student editStudent(Admin admin, Integer id, String sid, String name, Integer sex,
                               String nation, String major, String classroom, String cellphone,
                               String password, String buildingName, Integer roomNum, Integer bedNum) {


        // 通过id获取学生信息
        Student stu = studentMapper.selectById(id);

        // 如果stu为空，抛出id不存在异常
        if (stu == null) {
            throw new RespException(RespExceptionEnum.ID_NOT_EXISTS);
        }
        // 判断管理员权限
        if (admin.getRole() != 1 && !(admin.getRole() == 2 && admin.getBuildingId() == stu.getBuildingId())) {
            throw new RespException(RespExceptionEnum.NEED_PERMISSIONS);
        }

        Integer buildingId = null;
        Integer roomId = null;
        Integer bedId = null;


        if (!buildingName.equals("-1")) {
            // 判断宿舍楼是否存在
            QueryWrapper buildingQueryWrapper = new QueryWrapper();
            buildingQueryWrapper.eq("building_name", buildingName);
            Building building = buildingMapper.selectOne(buildingQueryWrapper);
            // 如果宿舍楼不存在，抛出异常
            if (building == null) {
                throw new RespException(RespExceptionEnum.BUILDING_NOT_EXISTS);
            }
            // 如果存在 保存building_id
            buildingId = building.getId();

            if (roomNum != -1) {
                // 判断宿舍是否存在
                QueryWrapper roomQueryWrapper = new QueryWrapper();
                roomQueryWrapper.eq("building_id", buildingId);
                roomQueryWrapper.eq("room_num", roomNum);
                Room room = roomMapper.selectOne(roomQueryWrapper);
                // 如果房间不存在，则抛出异常
                if (room == null) {
                    throw new RespException(RespExceptionEnum.ROOM_NOT_EXISTS);
                }
                // 如果存在， 保存room_id
                roomId = room.getId();
            } else {
                stu.setRoomId(null);
                stu.setBedId(null);
            }

            if (roomNum != -1 && bedNum != -1) {
                // 判断床位是否存在
                QueryWrapper bedQueryWrapper = new QueryWrapper();
                bedQueryWrapper.eq("building_id", buildingId);
                bedQueryWrapper.eq("room_id", roomId);
                bedQueryWrapper.eq("bed_num", bedNum);
                Bed bed = bedMapper.selectOne(bedQueryWrapper);
                // 如果床位不存在，则抛出异常
                if (bed == null) {
                    throw new RespException(RespExceptionEnum.BED_NOT_EXISTS);
                }
                // 如果存在，保存bed_id
                bedId = bed.getId();

                // 判断床位是否已经有人住
                QueryWrapper liveQueryWrapper = new QueryWrapper();
                liveQueryWrapper.eq("building_id", buildingId);
                liveQueryWrapper.eq("room_id", roomId);
                liveQueryWrapper.eq("bed_id", bedId);
                Student student1 = studentMapper.selectOne(liveQueryWrapper);
                // 如果已有人住，则抛出异常
                if (student1 != null && stu.getId() != student1.getId()) {
                    throw new RespException(RespExceptionEnum.BED_HAS_PERSON);
                }
            }
        }

        stu.setName(name);
        stu.setSex(sex);
        stu.setNation(nation);
        stu.setMajor(major);
        stu.setClassroom(classroom);
        stu.setCellphone(cellphone);

        // 判断密码是否有更改
        if (!password.equals(stu.getPassword())) {
            // 如果不同， 则需要将密码重新进行md5加密，封装到stu中
            stu.setPassword(MD5Utils.getMD5Str(password));
        }

        stu.setBuildingId(buildingId);
        stu.setRoomId(roomId);
        stu.setBedId(bedId);

        // 写入数据库
        int update = studentMapper.updateById(stu);

        // 如果写入数据不为1,抛出更新失败异常
        if (update != 1) {
            throw new RespException(RespExceptionEnum.UPDATE_FAILED);
        }

        return stu;
    }

    /**
     * 查询所有未分配宿舍学生信息
     *
     * @param admin 管理员信息
     * @return 学生列表
     */
    @Override
    public List<Student> selectNoBed(Admin admin) {

        Integer role = admin.getRole();
        List<Student> list = null;

        if (role == 1) {
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.isNull("bed_id");
            // 系统管理员可以查询所有宿舍信息
            list = studentMapper.selectList(queryWrapper);

        } else if (role == 2) {
            // 宿舍管理员只能查询所负责楼栋的宿舍信息
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("building_id", admin.getBuildingId());
            queryWrapper.isNull("bed_id");
            list = studentMapper.selectList(queryWrapper);

        } else {
            throw new RespException(RespExceptionEnum.NEED_PERMISSIONS);
        }

        // 将宿舍楼id、宿舍id、床位id转为对应的名字和号码
        for (Student student : list) {
            // 获取学生对应的buildingId, roomId, bedId
            Integer buildingId = student.getBuildingId();
            Integer roomId = student.getRoomId();
            Integer bedId = student.getBedId();

            if (student.getBuildingId() != null) {
                Building building = buildingMapper.selectById(buildingId);
                student.setBuildingName(building.getBuildingName());
            }
            if (student.getRoomId() != null) {
                Room room = roomMapper.selectById(roomId);
                student.setRoomNum(room.getRoomNum());
            }
            if (student.getBedId() != null) {
                Bed bed = bedMapper.selectById(bedId);
                student.setBedNum(bed.getBedNum());
            }
        }

        return list;
    }

    /**
     * 学生查询个人信息
     *
     * @param student 学生用户信息
     * @return 个人信息
     */
    @Override
    public Student selectSelf(Student student) {

        // 如果student为空，则抛出未登录异常
        if (student == null) {
            throw new RespException(RespExceptionEnum.NEED_LOGIN);
        }

        if (student.getBuildingId() != null) {
            Building building = buildingMapper.selectById(student.getBuildingId());
            student.setBuildingName(building.getBuildingName());
        }

        if (student.getRoomId() != null) {
            Room room = roomMapper.selectById(student.getRoomId());
            student.setRoomNum(room.getRoomNum());
        }

        if (student.getBedId() != null) {
            Bed bed = bedMapper.selectById(student.getBedId());
            student.setBedNum(bed.getBedNum());
        }

        return student;
    }

    /**
     * 查询室友信息
     *
     * @param student 学生用户信息
     * @return 学生列表
     */
    @Override
    public List<Student> selectRoommate(Student student) {

        // 如果student为空，则抛出未登录异常
        if (student == null) {
            throw new RespException(RespExceptionEnum.NEED_LOGIN);
        }

        List<Student> list = null;

        if (student.getRoomId() != null) {

            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("room_id", student.getRoomId());
            queryWrapper.orderByAsc("bed_id");
            list = studentMapper.selectList(queryWrapper);

            // 遍历列表，将buildingName,roomNum,bedNum添加进student实体类中
            for (Student stu : list) {

                if (stu.getBuildingId() != null) {
                    Building building = buildingMapper.selectById(stu.getBuildingId());
                    stu.setBuildingName(building.getBuildingName());
                }

                if (stu.getRoomId() != null) {
                    Room room = roomMapper.selectById(stu.getRoomId());
                    stu.setRoomNum(room.getRoomNum());
                }

                if (stu.getBedId() != null) {
                    Bed bed = bedMapper.selectById(stu.getBedId());
                    stu.setBedNum(bed.getBedNum());
                }
            }
        }

        return list;
    }

    /**
     * 查询所有班级列表
     *
     * @param admin
     * @return
     */
    @Override
    public List selectAllClassroom(Admin admin) {

        if (admin.getRole() != 1) {
            throw new RespException(RespExceptionEnum.NEED_PERMISSIONS);
        }

        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.groupBy("classroom");
        queryWrapper.select("classroom");
        List list = studentMapper.selectList(queryWrapper);

        return list;
    }

    /**
     * 查询所有未分配宿舍床位的学生人数
     *
     * @param admin
     * @param classroom
     * @param gender
     * @return
     */
    @Override
    public int selectNoBedStuCount(Admin admin, String classroom, Integer gender) {

        // 如果不是系统管理员，抛出权限不够异常
        if (admin.getRole() != 1) {
            throw new RespException(RespExceptionEnum.NEED_PERMISSIONS);
        }

        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("classroom", classroom);
        queryWrapper.eq("sex", gender);
        queryWrapper.isNull("bed_id");
        List list = studentMapper.selectList(queryWrapper);

        return list.size();
    }

    /**
     * 自动分配宿舍
     *
     * @param admin        管理员用户信息
     * @param classroom    班级
     * @param buildingName 宿舍楼
     * @param sex          性别
     * @return 已分配人数
     */
    @Override
    public int autoSetApartment(Admin admin, String classroom, String buildingName, int sex) {

        // 如果不是系统管理员，则抛出权限不够异常
        if (admin.getRole() != 1) {
            throw new RespException(RespExceptionEnum.NEED_PERMISSIONS);
        }

        // 查找当前班级，所有未分配学生
        QueryWrapper studentQueryWrapper = new QueryWrapper();
        studentQueryWrapper.eq("classroom", classroom);
        studentQueryWrapper.eq("sex", sex);
        studentQueryWrapper.isNull("bed_id");
        List stus = studentMapper.selectList(studentQueryWrapper);

        // 查找当前宿舍楼，所有空宿舍
        // 通过buildingName, 获得buildingId
        QueryWrapper buildingQueryWrapper = new QueryWrapper();
        buildingQueryWrapper.eq("building_name", buildingName);
        Building building = buildingMapper.selectOne(buildingQueryWrapper);

        // 查询该宿舍楼的所有房间列表
        QueryWrapper roomListQueryWrapper = new QueryWrapper();
        roomListQueryWrapper.eq("building_id", building.getId());
        List<Room> roomList = roomMapper.selectList(roomListQueryWrapper);

        // 定义空宿舍list
        List<Bed> beds = new ArrayList<>();

        // 遍历宿舍房间列表
        for (Room room : roomList) {
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("building_id", building.getId());
            queryWrapper.eq("room_id", room.getId());

            // 获得床位列表
            List<Bed> list = bedMapper.selectList(queryWrapper);

            // 如果有该房间有4个床位，则判断，4个床位是不是都没人居住
            if (list.size() != 4) {
                continue;
            }

            // 用来判断床位有人居住就跳出循环
            boolean flag = true;

            for (Bed bed : list) {
                QueryWrapper stuQueryWrapper = new QueryWrapper();
                stuQueryWrapper.eq("bed_id", bed.getId());
                Student student = studentMapper.selectOne(stuQueryWrapper);
                if (student != null) {
                    flag = true;
                    break;
                }
            }

            if (flag) {
                beds.add(list.get(0));
                beds.add(list.get(1));
                beds.add(list.get(2));
                beds.add(list.get(3));
            }

        }

        // 只分配空宿舍，将学生列表长度和床位列表长度均设置为4的倍数
        int stuSize = stus.size() / 4 * 4;
        int bedSize = beds.size() / 4 * 4;

        // 计算共分配的学生数量
        int i = 0;

        for (i = 0; i < stuSize; i++) {

            // 更新单个学生的buildingid，roomid，bedid
            Student stu = (Student) stus.get(i);
            stu.setBuildingId(beds.get(i).getBuildingId());
            stu.setRoomId(beds.get(i).getRoomId());
            stu.setBedId(beds.get(i).getId());
            studentMapper.updateById(stu);

            // 如果未分配人数，大于空床位数量，提前停止
            if (i >= bedSize) {
                break;
            }
        }

        return i;

    }
}
